home *** CD-ROM | disk | FTP | other *** search
/ PC Advisor 2011 May / PC Advisor 190 E.iso / pc / ESSENTIALS / VLC Media Player 1.1 / vlc-1.1.5-win32.exe / lua / intf / modules / host.lua < prev   
Encoding:
Text File  |  2010-11-13  |  9.9 KB  |  317 lines

  1. --[==========================================================================[
  2.  host.lua: VLC Lua interface command line host module
  3. --[==========================================================================[
  4.  Copyright (C) 2007 the VideoLAN team
  5.  $Id$
  6.  
  7.  Authors: Antoine Cellerier <dionoea at videolan dot org>
  8.  
  9.  This program is free software; you can redistribute it and/or modify
  10.  it under the terms of the GNU General Public License as published by
  11.  the Free Software Foundation; either version 2 of the License, or
  12.  (at your option) any later version.
  13.  
  14.  This program is distributed in the hope that it will be useful,
  15.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  GNU General Public License for more details.
  18.  
  19.  You should have received a copy of the GNU General Public License
  20.  along with this program; if not, write to the Free Software
  21.  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22. --]==========================================================================]
  23.  
  24. --[==========================================================================[
  25. Example use:
  26.  
  27.     require "host"
  28.     h = host.host()
  29.  
  30.     -- Bypass any authentication
  31.     function on_password( client )
  32.         client:switch_status( host.status.read )
  33.     end
  34.     h.status_callbacks[host.status.password] = on_password
  35.  
  36.     h:listen( "localhost:4212" )
  37.     h:listen( "*console" )
  38.     --or h:listen( { "localhost:4212", "*console" } )
  39.  
  40.     -- The main loop
  41.     while not vlc.misc.should_die() do
  42.         -- accept new connections and select active clients
  43.         local write, read = h:accept_and_select()
  44.  
  45.         -- handle clients in write mode
  46.         for _, client in pairs(write) do
  47.             client:send()
  48.             client.buffer = ""
  49.             client:switch_status( host.status.read )
  50.         end
  51.  
  52.         -- handle clients in read mode
  53.         for _, client in pairs(read) do
  54.             local str = client:recv(1000)
  55.             str = string.gsub(str,"\r?\n$","")
  56.             client.buffer = "Got `"..str.."'.\r\n"
  57.             client:switch_status( host.status.write )
  58.         end
  59.     end
  60.  
  61. For complete examples see existing VLC Lua interface modules (ie telnet.lua)
  62. --]==========================================================================]
  63.  
  64. module("host",package.seeall)
  65.  
  66. status = { init = 0, read = 1, write = 2, password = 3 }
  67. client_type = { net = 1, stdio = 2, fifo = 3 }
  68.  
  69. function host()
  70.     -- private data
  71.     local clients = {}
  72.     local listeners = {}
  73.     local status_callbacks = {}
  74.  
  75.     -- private methods
  76.     local function fd_client( client )
  77.         if client.status == status.read then
  78.             return client.rfd
  79.         else -- status.write
  80.             return client.wfd
  81.         end
  82.     end
  83.  
  84.     local function send( client, data, len )
  85.         if len then
  86.             return vlc.net.send( client.wfd, data, len )
  87.         else
  88.             return vlc.net.send( client.wfd, data or client.buffer )
  89.         end
  90.     end
  91.  
  92.     local function recv( client, len )
  93.         if len then
  94.             return vlc.net.recv( client.rfd, len )
  95.         else
  96.             return vlc.net.recv( client.rfd )
  97.         end
  98.     end
  99.  
  100.     local function write( client, data )
  101.         return vlc.net.write( client.wfd, data or client.buffer )
  102.     end
  103.  
  104.     local function read( client, len )
  105.         if len then
  106.             return vlc.net.read( client.rfd, len )
  107.         else
  108.             return vlc.net.read( client.rfd )
  109.         end
  110.     end
  111.  
  112.     local function del_client( client )
  113.         if client.type == client_type.stdio then
  114.             client:send( "Cannot delete stdin/stdout client.\n" )
  115.             return
  116.         end
  117.         for i, c in pairs(clients) do
  118.             if c == client then
  119.                 if client.type == client_type.net then
  120.                     if client.wfd ~= client.rfd then
  121.                         vlc.net.close( client.rfd )
  122.                     end
  123.                     vlc.net.close( client.wfd )
  124.                 end
  125.                 clients[i] = nil
  126.                 return
  127.             end
  128.         end
  129.         vlc.msg.err("couldn't find client to remove.")
  130.     end
  131.     
  132.     local function switch_status( client, s )
  133.         if client.status == s then return end
  134.         client.status = s
  135.         if status_callbacks[s] then
  136.             status_callbacks[s]( client )
  137.         end
  138.     end
  139.  
  140.     -- append a line to a client's (output) buffer
  141.     local function append( client, string )
  142.         client.buffer = client.buffer .. string .. "\r\n"
  143.     end
  144.  
  145.     local function new_client( h, fd, wfd, t )
  146.         if fd < 0 then return end
  147.         local w, r
  148.         if t == client_type.net then
  149.             w = send
  150.             r = recv
  151.         else if t == client_type.stdio or t == client_type.fifo then
  152.             w = write
  153.             r = read
  154.         else
  155.             error("Unknown client type", t )
  156.         end end
  157.         local client = { -- data
  158.                          rfd = fd,
  159.                          wfd = wfd or fd,
  160.                          status = status.init,
  161.                          buffer = "",
  162.                          cmds = "",
  163.                          type = t,
  164.                          -- methods
  165.                          fd = fd_client,
  166.                          send = w,
  167.                          recv = r,
  168.                          del = del_client,
  169.                          switch_status = switch_status,
  170.                          append = append,
  171.                        }
  172.         client:send( "VLC media player "..vlc.misc.version().."\n" )
  173.         table.insert(clients, client)
  174.         client:switch_status(status.password)
  175.     end
  176.  
  177.     -- public methods
  178.     local function _listen_tcp( h, host, port )
  179.         if listeners.tcp and listeners.tcp[host]
  180.                          and listeners.tcp[host][port] then
  181.             error("Already listening on tcp host `"..host..":"..tostring(port).."'")
  182.         end
  183.         if not listeners.tcp then
  184.             listeners.tcp = {}
  185.         end
  186.         if not listeners.tcp[host] then
  187.             listeners.tcp[host] = {}
  188.         end
  189.         local listener = vlc.net.listen_tcp( host, port )
  190.         listeners.tcp[host][port] = listener
  191.         if not listeners.tcp.list then
  192.             -- FIXME: if host == "list" we'll have a problem
  193.             listeners.tcp.list = {}
  194.             local m = { __mode = "v" } -- week values
  195.             setmetatable( listeners.tcp.list, m )
  196.         end
  197.         table.insert( listeners.tcp.list, listener )
  198.     end
  199.  
  200.     local function _listen_stdio( h )
  201.         
  202.         if listeners.stdio then
  203.             error("Already listening on stdio")
  204.         end
  205.         new_client( h, 0, 1, client_type.stdio )
  206.         listeners.stdio = true
  207.     end
  208.  
  209.     local function _listen( h, url )
  210.         if type(url)==type({}) then
  211.             for _,u in pairs(url) do
  212.                 h:listen( u )
  213.             end
  214.         else
  215.             vlc.msg.info( "Listening on host \""..url.."\"." )
  216.             if url == "*console" then
  217.                 h:listen_stdio()
  218.             else
  219.                 u = vlc.net.url_parse( url )
  220.                 h:listen_tcp( u.host, u.port )
  221.             end
  222.         end
  223.     end
  224.  
  225.     local function _accept_and_select( h, timeout )
  226.         local function filter_client( fds, status, event )
  227.             for _, client in pairs(clients) do
  228.                 if client.status == status then
  229.                     fds[client:fd()] = event
  230.                 end
  231.             end
  232.         end
  233.  
  234.         local pollfds = {}
  235.         filter_client( pollfds, status.read, vlc.net.POLLIN )
  236.         filter_client( pollfds, status.password, vlc.net.POLLIN )
  237.         filter_client( pollfds, status.write, vlc.net.POLLOUT )
  238.  
  239.         if listeners.tcp then
  240.             for _, listener in pairs(listeners.tcp.list) do
  241.                 for _, fd in pairs({listener:fds()}) do
  242.                     pollfds[fd] = vlc.net.POLLIN
  243.                 end
  244.             end
  245.         end
  246.  
  247.         local ret = vlc.net.poll( pollfds, timeout or -1 )
  248.         local wclients = {}
  249.         local rclients = {}
  250.         if ret > 0 then
  251.             for _, client in pairs(clients) do
  252.                 if pollfds[client:fd()] == vlc.net.POLLOUT then
  253.                     table.insert(wclients,client)
  254.                 elseif pollfds[client:fd()] == vlc.net.POLLIN then
  255.                     table.insert(rclients,client)
  256.                 else
  257.                     del_client( client )
  258.                 end
  259.             end
  260.             if listeners.tcp then
  261.                 for _, listener in pairs(listeners.tcp.list) do
  262.                     for _, fd in pairs({listener:fds()}) do
  263.                         if pollfds[fd] == vlc.net.POLLIN then
  264.                             local afd = listener:accept()
  265.                             new_client( h, afd, afd, client_type.net )
  266.                             break
  267.                         end
  268.                     end
  269.                 end
  270.             end
  271.         end
  272.  
  273.         return wclients, rclients
  274.     end
  275.  
  276.     local function destructor( h )
  277.         print "destructor"
  278.         for _,client in pairs(clients) do
  279.             client:send("Shutting down.")
  280.             if client.type == client_type.tcp then
  281.                 if client.wfd ~= client.rfd then
  282.                     vlc.net.close(client.rfd)
  283.                 end
  284.                 vlc.net.close(client.wfd)
  285.             end
  286.         end
  287.     end
  288.  
  289.     local function _broadcast( h, msg )
  290.         for _,client in pairs(clients) do
  291.             client:send( msg )
  292.         end
  293.     end
  294.  
  295.     -- the instance
  296.     local h = { -- data
  297.                 status_callbacks = status_callbacks,
  298.                 -- methods
  299.                 listen = _listen,
  300.                 listen_tcp = _listen_tcp,
  301.                 listen_stdio = _listen_stdio,
  302.                 accept_and_select = _accept_and_select,
  303.                 broadcast = _broadcast,
  304.               }
  305.  
  306.     -- the metatable
  307.     local m = { -- data
  308.                 __metatable = "Nothing to see here. Move along.",
  309.                 -- methods
  310.                 __gc = destructor,
  311.               }
  312.  
  313.     setmetatable( h, m )
  314.  
  315.     return h
  316. end
  317.